Skip to content

feat(orpc): add oRPC integration#344

Open
HugoRCD wants to merge 6 commits into
mainfrom
feat/orpc-integration
Open

feat(orpc): add oRPC integration#344
HugoRCD wants to merge 6 commits into
mainfrom
feat/orpc-integration

Conversation

@HugoRCD
Copy link
Copy Markdown
Owner

@HugoRCD HugoRCD commented May 10, 2026

🔗 Linked issue

Closes #297

📚 Description

Adds evlog/orpc so each oRPC procedure call becomes a single wide event. Two complementary primitives that mirror oRPC's two layers:

  • withEvlog(handler) — wraps any handler exposing .handle(request, options) from @orpc/server/fetch (RPCHandler, OpenAPIHandler, custom). The wrapped handler is a transparent Proxy, so it stays an instance of the original (wrapped instanceof RPCHandler === true). Each matched request creates a request-scoped logger, injects it as context.log into the oRPC initial context, and emits one wide event with the standard pipeline (drain, enrich, keep, include/exclude, routes, plugins). Excluded routes still receive a no-op logger so procedures never crash on missing fields.
  • evlog() — procedure middleware (os.use(evlog())). Tags the wide event with operation (the procedure path joined with .), forwards the request logger as context.log, and promotes the level to error when a procedure throws — before re-throwing so oRPC's own ORPCError path runs untouched.
import { os } from '@orpc/server'
import { RPCHandler } from '@orpc/server/fetch'
import { evlog, withEvlog, type EvlogOrpcContext } from 'evlog/orpc'

const base = os.$context<EvlogOrpcContext>().use(evlog())

const router = {
  ping: base.handler(({ context }) => {
    context.log.set({ pinged: true })
    return { ok: true }
  }),
}

const handler = withEvlog(new RPCHandler(router))

export default async function fetch(request: Request) {
  const { matched, response } = await handler.handle(request, { prefix: '/rpc' })
  return matched ? response : new Response('Not Found', { status: 404 })
}

useLogger() is exposed for off-context access (utility modules, deep service functions). EvlogOrpcContext plugs into os.$context() for typed access.

Followed .agents/skills/create-framework-integration/SKILL.md — all 16 touchpoints addressed: source, build config, exports, peer dep, 18 integration tests, framework docs page (3.integrate/frameworks/15.orpc.md), overview / installation / landing / FeatureFrameworks updates, README + Framework Support table, review-logging-patterns skill update, runnable example app at examples/orpc/ (Bun + OpenAPIHandler + PostHog drain + test UI), root example:orpc script, and the orpc scope added to semantic-pull-request.yml + the PR template.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Summary by CodeRabbit

  • New Features

    • oRPC integration: per-request wide-event logging via a handler wrapper and procedure middleware, request-scoped logger access, operation tagging, error-level escalation on throws, enrichment, draining, and tail-sampling.
  • Examples

    • New oRPC example app with dev script, interactive UI, sample endpoints, and logging/error demonstrations.
  • Documentation

    • Comprehensive oRPC docs, quickstart, and updated framework listings and landing/start guides.
  • Tests

    • Added tests validating oRPC logging, sampling, filtering, and error handling.
  • Chores

    • CI/PR scopes and example dev script updated to include orpc.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
evlog-docs Ready Ready Preview, Comment, Open in v0 May 10, 2026 8:49pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
just-use-evlog Skipped Skipped May 10, 2026 8:49pm

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

Unknown scope "orpc" found in pull request title "feat(orpc): add oRPC integration". Scope must match one of: ai, axiom, bench, better-auth, better-stack, core, datadog, deps, docs, dx, elysia, express, fastify, fs, hono, hyperdx, nestjs, next, nitro, nuxt, otlp, playground, posthog, react-router, release, repo, sentry, stream, sveltekit, tanstack-start, vite, workers.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 09fb0dac-949f-4dd3-9de2-eafc84b9e62e

📥 Commits

Reviewing files that changed from the base of the PR and between 0c03927 and cc9ccb8.

📒 Files selected for processing (1)
  • apps/docs/content/3.integrate/frameworks/15.orpc.md

📝 Walkthrough

Walkthrough

This PR introduces oRPC framework integration to evlog, adding an evlog/orpc module with withEvlog() handler wrapper, evlog() procedure middleware, useLogger() utility, EvlogOrpcContext typing, package/build updates, tests, docs, and an example workspace.

Changes

oRPC Integration Feature

Layer / File(s) Summary
Type Contracts & Framework Integration
packages/evlog/src/orpc/index.ts, packages/evlog/package.json
New evlog/orpc module exports withEvlog() handler wrapper, evlog() procedure middleware, useLogger() utility, and EvlogOrpcContext type. Package adds ./orpc export path and type mapping.
Build & Dependency Configuration
packages/evlog/package.json, packages/evlog/tsdown.config.ts, examples/orpc/tsconfig.json
Adds @orpc/server to peerDependencies (optional) and @orpc/client/@orpc/server to devDependencies; adds tsdown entry for orpc/index and marks @orpc/server and @orpc/server/fetch as external. Also adds example tsconfig and root example:orpc script.
Test Coverage
packages/evlog/test/frameworks/orpc.test.ts
Comprehensive Vitest suite covering handler wrapping, wide event emission, procedure middleware behavior, logger visibility and ALS access, route include/exclude filtering, drain/enrich/keep pipelines, header filtering, and error handling.
Core Framework Documentation
apps/docs/content/3.integrate/frameworks/15.orpc.md
Full integration guide covering primitives, Quick Start, typed context, wide events semantics, logger access patterns (context.log/useLogger()), structured error handling, drain/enrich/sampling/filtering, and local run instructions.
Documentation Integration & References
packages/evlog/README.md, apps/docs/content/..., apps/docs/app/components/features/FeatureFrameworks.vue
Adds oRPC to README, framework overview/table/cards, landing page example, installation guide card, skills doc, and the FeatureFrameworks UI tab.
Example Project
examples/orpc/package.json, examples/orpc/tsconfig.json, examples/orpc/src/index.ts, examples/orpc/src/ui.ts, examples/orpc/README.md, package.json
New Bun-based example workspace demonstrating evlog + oRPC wiring, typed errors, handler wrapping with withEvlog, PostHog drain integration, event enrichment and tail-sampling, interactive UI, and a root example:orpc dev script.
PR Metadata & Configuration
.changeset/orpc-integration.md, .github/pull_request_template.md, .github/workflows/semantic-pull-request.yml
Changeset documents the minor feature and recognizes orpc in PR template and semantic PR workflow scopes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

documentation, dependencies

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(orpc): add oRPC integration' follows conventional commits format and clearly describes the main change.
Description check ✅ Passed The PR description comprehensively covers the change, includes a linked issue, detailed explanation of the two main primitives, code example, and completed checklist items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/orpc-integration

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

Benchmark report

Bundle size

Threshold: 5% · 🔴 larger · 🟡 warning · 🟢 smaller · ⚪ unchanged · 🆕 new

Status Entry Base (gzip) Current (gzip) Change Raw delta
framework/express 727 B 739 B +1.7% +49 B
framework/nestjs 1.25 kB 1.26 kB +0.4% +41 B
toolkit 781 B 783 B +0.3% 0 B
adapter/better-stack 1.26 kB 1.26 kB +0.2% 0 B
framework/fastify 1.02 kB 1.02 kB +0.2% 0 B
framework/hono 615 B 616 B +0.2% 0 B
adapter/posthog 1.47 kB 1.47 kB +0.1% 0 B
adapter/axiom 1.50 kB 1.50 kB +0.1% 0 B
adapter/datadog 2.48 kB 2.48 kB +0.1% 0 B
adapter/otlp 2.14 kB 2.14 kB +0.1% 0 B
core (index) 2.15 kB 2.16 kB +0.1% 0 B
adapter/hyperdx 1.18 kB 1.18 kB +0.1% 0 B
workers 1.30 kB 1.31 kB +0.1% 0 B
framework/sveltekit 1.59 kB 1.59 kB +0.1% 0 B
framework/next 5.20 kB 5.20 kB +0.0% 0 B
framework/ai 4.67 kB 4.67 kB 0.0% 0 B
adapter/fs 3.35 kB 3.35 kB 0.0% 0 B
adapter/sentry 2.40 kB 2.40 kB 0.0% 0 B
framework/vite 2.40 kB 2.40 kB 0.0% 0 B
enrichers 1.99 kB 1.99 kB 0.0% 0 B
utils 1.58 kB 1.58 kB 0.0% 0 B
error 1.57 kB 1.57 kB 0.0% 0 B
pipeline 1.35 kB 1.35 kB 0.0% 0 B
framework/elysia 1.33 kB 1.33 kB 0.0% 0 B
http 1.24 kB 1.24 kB 0.0% 0 B
browser 289 B 289 B 0.0% 0 B
client 128 B 128 B 0.0% 0 B
types 31 B 31 B 0.0% 0 B
framework/nitro 7.16 kB 7.16 kB -0.0% 0 B
logger 229 B 225 B -1.7% 0 B
Total 54.33 kB 54.36 kB +0.1% +90 B

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 10, 2026

npm i https://pkg.pr.new/evlog@344
npm i https://pkg.pr.new/@evlog/nuxthub@344

commit: cc9ccb8

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/orpc/src/ui.ts`:
- Around line 196-205: The syntaxHighlight function currently builds HTML from
raw JSON pieces and is later assigned to innerHTML, creating an XSS risk; update
syntaxHighlight (and where its output is set to innerHTML) to HTML-escape any
dynamic content (strings/keys/values) before wrapping them in span tags or,
better, build DOM nodes and set textContent for values and class names for
styling instead of concatenating HTML; ensure all occurrences of
string/key/number/boolean/null matches returned by syntaxHighlight are sanitized
(escape &, <, >, ", ') or replaced via textContent to eliminate script
injection.

In `@packages/evlog/src/orpc/index.ts`:
- Around line 11-13: Add JSDoc comments for the public exports EvlogOrpcOptions
and useLogger: for EvlogOrpcOptions (alias of BaseEvlogOptions) add a one-line
description explaining its purpose and any important fields/inheritance; for
useLogger add a short description of what it returns/does, document its
parameters and return type, and include any thrown errors or usage notes. Place
the comments immediately above the `export type EvlogOrpcOptions =
BaseEvlogOptions` and `export { useLogger }` lines so IDEs and generated docs
pick them up.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a1ce7e61-8a34-42ac-80f9-290671a8da71

📥 Commits

Reviewing files that changed from the base of the PR and between 31b6b31 and 4045c83.

⛔ Files ignored due to path filters (2)
  • packages/evlog/test/toolkit/__snapshots__/api-surface.test.ts.snap is excluded by !**/*.snap
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • .changeset/orpc-integration.md
  • .github/pull_request_template.md
  • .github/workflows/semantic-pull-request.yml
  • apps/docs/app/components/features/FeatureFrameworks.vue
  • apps/docs/content/0.landing.md
  • apps/docs/content/1.start/3.installation.md
  • apps/docs/content/3.integrate/frameworks/00.overview.md
  • apps/docs/content/3.integrate/frameworks/15.orpc.md
  • apps/docs/skills/review-logging-patterns/SKILL.md
  • examples/orpc/README.md
  • examples/orpc/package.json
  • examples/orpc/src/index.ts
  • examples/orpc/src/ui.ts
  • examples/orpc/tsconfig.json
  • package.json
  • packages/evlog/README.md
  • packages/evlog/package.json
  • packages/evlog/src/orpc/index.ts
  • packages/evlog/test/frameworks/orpc.test.ts
  • packages/evlog/tsdown.config.ts

Comment thread examples/orpc/src/ui.ts
Comment on lines +196 to +205
function syntaxHighlight(json) {
return JSON.stringify(json, null, 2)
.replace(/("(\\\\u[a-fA-F0-9]{4}|\\\\[^u]|[^\\\\"])*")(\\s*:)?/g, (match, str, _, colon) => {
if (colon) return '<span class="key">' + str + '</span>' + colon
return '<span class="string">' + str + '</span>'
})
.replace(/\\b(true|false)\\b/g, '<span class="boolean">$1</span>')
.replace(/\\bnull\\b/g, '<span class="null">null</span>')
.replace(/\\b(-?\\d+\\.?\\d*([eE][+-]?\\d+)?)\\b/g, '<span class="number">$1</span>')
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Escape response content before writing to innerHTML (XSS risk).

syntaxHighlight() builds HTML from response data, and Line 239 injects it with innerHTML. If a response string contains HTML/script payload, it can execute in the page.

🔒 Proposed fix
+    function escapeHtml(value) {
+      return value
+        .replace(/&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/"/g, '&quot;')
+        .replace(/'/g, '&#39;')
+    }
+
     function syntaxHighlight(json) {
       return JSON.stringify(json, null, 2)
         .replace(/("(\\\\u[a-fA-F0-9]{4}|\\\\[^u]|[^\\\\"])*")(\\s*:)?/g, (match, str, _, colon) => {
-          if (colon) return '<span class="key">' + str + '</span>' + colon
-          return '<span class="string">' + str + '</span>'
+          const safe = escapeHtml(str)
+          if (colon) return '<span class="key">' + safe + '</span>' + colon
+          return '<span class="string">' + safe + '</span>'
         })
         .replace(/\\b(true|false)\\b/g, '<span class="boolean">$1</span>')
         .replace(/\\bnull\\b/g, '<span class="null">null</span>')
         .replace(/\\b(-?\\d+\\.?\\d*([eE][+-]?\\d+)?)\\b/g, '<span class="number">$1</span>')
     }

Also applies to: 239-239

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/orpc/src/ui.ts` around lines 196 - 205, The syntaxHighlight function
currently builds HTML from raw JSON pieces and is later assigned to innerHTML,
creating an XSS risk; update syntaxHighlight (and where its output is set to
innerHTML) to HTML-escape any dynamic content (strings/keys/values) before
wrapping them in span tags or, better, build DOM nodes and set textContent for
values and class names for styling instead of concatenating HTML; ensure all
occurrences of string/key/number/boolean/null matches returned by
syntaxHighlight are sanitized (escape &, <, >, ", ') or replaced via textContent
to eliminate script injection.

Comment on lines +11 to +13
export type EvlogOrpcOptions = BaseEvlogOptions

export { useLogger }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add JSDoc for EvlogOrpcOptions and useLogger exports.

These are public APIs but currently undocumented in this module.

📝 Proposed fix
+/**
+ * Options accepted by `withEvlog()` for oRPC request instrumentation.
+ */
 export type EvlogOrpcOptions = BaseEvlogOptions
 
+/**
+ * Access the current request-scoped logger outside oRPC context callbacks.
+ */
 export { useLogger }

As per coding guidelines, packages/evlog/src/**/*.{ts,tsx}: Add JSDoc comments on all public APIs.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type EvlogOrpcOptions = BaseEvlogOptions
export { useLogger }
/**
* Options accepted by `withEvlog()` for oRPC request instrumentation.
*/
export type EvlogOrpcOptions = BaseEvlogOptions
/**
* Access the current request-scoped logger outside oRPC context callbacks.
*/
export { useLogger }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/evlog/src/orpc/index.ts` around lines 11 - 13, Add JSDoc comments
for the public exports EvlogOrpcOptions and useLogger: for EvlogOrpcOptions
(alias of BaseEvlogOptions) add a one-line description explaining its purpose
and any important fields/inheritance; for useLogger add a short description of
what it returns/does, document its parameters and return type, and include any
thrown errors or usage notes. Place the comments immediately above the `export
type EvlogOrpcOptions = BaseEvlogOptions` and `export { useLogger }` lines so
IDEs and generated docs pick them up.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
examples/orpc/src/ui.ts (1)

199-204: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Escape highlighted JSON tokens before writing to innerHTML (XSS).

At Line 242, untrusted response content is rendered via innerHTML, and syntaxHighlight() currently injects raw string/key tokens into HTML spans. This allows scriptable payloads in JSON strings.

🔒 Proposed minimal fix
+    function escapeHtml(value) {
+      return value
+        .replace(/&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/"/g, '&quot;')
+        .replace(/'/g, '&#39;')
+    }
+
     function syntaxHighlight(json) {
       return JSON.stringify(json, null, 2)
         .replace(/("(\\\\u[a-fA-F0-9]{4}|\\\\[^u]|[^\\\\"])*")(\\s*:)?/g, (match, str, _, colon) => {
-          if (colon) return '<span class="key">' + str + '</span>' + colon
-          return '<span class="string">' + str + '</span>'
+          const safe = escapeHtml(str)
+          if (colon) return '<span class="key">' + safe + '</span>' + colon
+          return '<span class="string">' + safe + '</span>'
         })
         .replace(/\\b(true|false)\\b/g, '<span class="boolean">$1</span>')
         .replace(/\\bnull\\b/g, '<span class="null">null</span>')
         .replace(/\\b(-?\\d+\\.?\\d*([eE][+-]?\\d+)?)\\b/g, '<span class="number">$1</span>')
     }

Also applies to: 242-242

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/orpc/src/ui.ts` around lines 199 - 204, The syntaxHighlight function
is inserting raw JSON tokens into HTML, enabling XSS when that output is
assigned to innerHTML; update syntaxHighlight (and any call sites that set
innerHTML with its result) to escape HTML special characters (&, <, >, ", ') in
the captured string/key tokens before wrapping them in spans or, alternatively,
build DOM nodes and set textContent instead of interpolating raw strings,
ensuring all occurrences of string and key values in syntaxHighlight are
properly escaped before returning HTML.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/orpc/src/index.ts`:
- Around line 49-55: The middleware `authed` is declared `async` but doesn't
`await`, causing a `require-await` lint error; remove the `async` modifier on
the arrow function passed to `base.use` (i.e., change `async ({ context, next })
=> { ... }` to `({ context, next }) => { ... }`) while keeping the body intact
(creating the `AuthedUser`, calling `context.log.set`, and returning `next({
context: { ...context, user } })`) so the function still returns the Promise
from `next`.

---

Duplicate comments:
In `@examples/orpc/src/ui.ts`:
- Around line 199-204: The syntaxHighlight function is inserting raw JSON tokens
into HTML, enabling XSS when that output is assigned to innerHTML; update
syntaxHighlight (and any call sites that set innerHTML with its result) to
escape HTML special characters (&, <, >, ", ') in the captured string/key tokens
before wrapping them in spans or, alternatively, build DOM nodes and set
textContent instead of interpolating raw strings, ensuring all occurrences of
string and key values in syntaxHighlight are properly escaped before returning
HTML.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4f0c0cf0-b5bc-47f1-81f3-98278fe528d4

📥 Commits

Reviewing files that changed from the base of the PR and between 4045c83 and 7c3da27.

📒 Files selected for processing (4)
  • apps/docs/content/3.integrate/frameworks/15.orpc.md
  • examples/orpc/README.md
  • examples/orpc/src/index.ts
  • examples/orpc/src/ui.ts

Comment on lines +49 to +55
const authed = base.use(async ({ context, next }) => {
const user: AuthedUser = { id: 'u-1', name: 'Alice', role: 'admin', apiKey: 'demo' }
context.log.set({ auth: { ok: true, userId: user.id, role: user.role } })
return next({
context: { ...context, user },
})
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove unnecessary async to satisfy require-await and keep lint green.

Line 49 declares an async middleware but does not await anything; this triggers the reported ESLint error.

✅ Minimal patch
-const authed = base.use(async ({ context, next }) => {
+const authed = base.use(({ context, next }) => {
   const user: AuthedUser = { id: 'u-1', name: 'Alice', role: 'admin', apiKey: 'demo' }
   context.log.set({ auth: { ok: true, userId: user.id, role: user.role } })
   return next({
     context: { ...context, user },
   })
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const authed = base.use(async ({ context, next }) => {
const user: AuthedUser = { id: 'u-1', name: 'Alice', role: 'admin', apiKey: 'demo' }
context.log.set({ auth: { ok: true, userId: user.id, role: user.role } })
return next({
context: { ...context, user },
})
})
const authed = base.use(({ context, next }) => {
const user: AuthedUser = { id: 'u-1', name: 'Alice', role: 'admin', apiKey: 'demo' }
context.log.set({ auth: { ok: true, userId: user.id, role: user.role } })
return next({
context: { ...context, user },
})
})
🧰 Tools
🪛 ESLint

[error] 49-49: Async arrow function has no 'await' expression.

(require-await)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/orpc/src/index.ts` around lines 49 - 55, The middleware `authed` is
declared `async` but doesn't `await`, causing a `require-await` lint error;
remove the `async` modifier on the arrow function passed to `base.use` (i.e.,
change `async ({ context, next }) => { ... }` to `({ context, next }) => { ...
}`) while keeping the body intact (creating the `AuthedUser`, calling
`context.log.set`, and returning `next({ context: { ...context, user } })`) so
the function still returns the Promise from `next`.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
examples/orpc/src/index.ts (1)

62-68: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove unnecessary async from middleware (require-await).

The middleware returns next(...) directly and does not await anything, so this triggers lint failure.

✅ Minimal fix
-const authed = base.use(async ({ context, next }) => {
+const authed = base.use(({ context, next }) => {
   const user: AuthedUser = { id: 'u-1', name: 'Alice', role: 'admin', apiKey: 'demo' }
   context.log.set({ auth: { ok: true, userId: user.id, role: user.role } })
   return next({
     context: { ...context, user },
   })
 })
#!/bin/bash
# Verify there are no base.use async middlewares without await in this file.
rg -nP "base\.use\(async\s*\(\{[^)]*\}\)\s*=>" examples/orpc/src/index.ts
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/orpc/src/index.ts` around lines 62 - 68, The middleware "authed"
passed to base.use is declared async but never awaits, causing a require-await
lint error; change the declaration to a synchronous function by removing the
async keyword from the authed middleware (i.e., update the base.use handler
signature that currently reads "async ({ context, next }) =>" to a plain "({
context, next }) =>"), leaving the body and the return of next({ context: {
...context, user } }) unchanged so behavior is preserved.
examples/orpc/src/ui.ts (1)

209-218: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Escape dynamic JSON tokens before writing highlighted output to innerHTML.

Response data is interpolated into HTML spans without escaping, so HTML/script payloads in response strings can execute in the page.

🔒 Minimal fix
+    function escapeHtml(value) {
+      return value
+        .replace(/&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/"/g, '&quot;')
+        .replace(/'/g, '&#39;')
+    }
+
     function syntaxHighlight(json) {
       return JSON.stringify(json, null, 2)
         .replace(/("(\\\\u[a-fA-F0-9]{4}|\\\\[^u]|[^\\\\"])*")(\\s*:)?/g, (match, str, _, colon) => {
-          if (colon) return '<span class="key">' + str + '</span>' + colon
-          return '<span class="string">' + str + '</span>'
+          const safe = escapeHtml(str)
+          if (colon) return '<span class="key">' + safe + '</span>' + colon
+          return '<span class="string">' + safe + '</span>'
         })
         .replace(/\\b(true|false)\\b/g, '<span class="boolean">$1</span>')
         .replace(/\\bnull\\b/g, '<span class="null">null</span>')
         .replace(/\\b(-?\\d+\\.?\\d*([eE][+-]?\\d+)?)\\b/g, '<span class="number">$1</span>')
     }

Also applies to: 252-252

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/orpc/src/ui.ts` around lines 209 - 218, The syntaxHighlight function
builds HTML with unescaped JSON pieces, enabling XSS when its return is assigned
to innerHTML; fix by HTML-escaping dynamic tokens before wrapping them in spans
(create/ use an escapeHtml helper and apply it to the captured string token
`str` in the first replace and to the captured groups used for
numbers/booleans/null in the other replaces), so the replacement callbacks use
the escaped value rather than raw match; ensure you escape quotes, ampersands,
<, > and slashes when producing the span contents.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/orpc/src/ui.ts`:
- Around line 244-257: The code currently assumes every response is JSON (using
await res.json()) and treats parse failures as network errors; change the logic
so after receiving res you check the Content-Type (e.g.,
res.headers.get('content-type')) and if it contains "application/json" parse
with res.json() and render via syntaxHighlight(data), otherwise use await
res.text() and render the plain text/HTML into el.body (and set an appropriate
class like 'response-body text' or similar); ensure only real network exceptions
fall into the catch block and preserve updating el.header, el.status,
el.methodPath, and el.timing for non-JSON responses as well (references:
variables/res object, el, syntaxHighlight, method, path, ms).

---

Duplicate comments:
In `@examples/orpc/src/index.ts`:
- Around line 62-68: The middleware "authed" passed to base.use is declared
async but never awaits, causing a require-await lint error; change the
declaration to a synchronous function by removing the async keyword from the
authed middleware (i.e., update the base.use handler signature that currently
reads "async ({ context, next }) =>" to a plain "({ context, next }) =>"),
leaving the body and the return of next({ context: { ...context, user } })
unchanged so behavior is preserved.

In `@examples/orpc/src/ui.ts`:
- Around line 209-218: The syntaxHighlight function builds HTML with unescaped
JSON pieces, enabling XSS when its return is assigned to innerHTML; fix by
HTML-escaping dynamic tokens before wrapping them in spans (create/ use an
escapeHtml helper and apply it to the captured string token `str` in the first
replace and to the captured groups used for numbers/booleans/null in the other
replaces), so the replacement callbacks use the escaped value rather than raw
match; ensure you escape quotes, ampersands, <, > and slashes when producing the
span contents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 27675694-6843-47e3-88c1-43fbfca706e1

📥 Commits

Reviewing files that changed from the base of the PR and between 7c3da27 and 6532944.

📒 Files selected for processing (3)
  • apps/docs/content/3.integrate/frameworks/15.orpc.md
  • examples/orpc/src/index.ts
  • examples/orpc/src/ui.ts

Comment thread examples/orpc/src/ui.ts
Comment on lines +244 to +257
const data = await res.json()

el.header.style.display = 'flex'
el.status.textContent = res.status
el.status.className = 'status status-' + (res.status < 300 ? '2xx' : res.status < 500 ? '4xx' : '5xx')
el.methodPath.textContent = method + ' ' + path
el.timing.textContent = ms + 'ms'
el.body.className = 'response-body'
el.body.innerHTML = syntaxHighlight(data)
} catch (err) {
el.header.style.display = 'none'
el.body.className = 'response-body'
el.body.textContent = 'Network error: ' + err.message
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle non-JSON responses explicitly instead of reporting them as “Network error”.

Line 244 assumes JSON for every response. A valid text/HTML error body (e.g., 404 text) throws during parsing and is misclassified in the catch branch.

✅ Minimal fix
-        const data = await res.json()
+        const contentType = res.headers.get('content-type') || ''
+        const data = contentType.includes('application/json')
+          ? await res.json()
+          : await res.text()
...
-        el.body.innerHTML = syntaxHighlight(data)
+        if (typeof data === 'string') {
+          el.body.textContent = data
+        } else {
+          el.body.innerHTML = syntaxHighlight(data)
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const data = await res.json()
el.header.style.display = 'flex'
el.status.textContent = res.status
el.status.className = 'status status-' + (res.status < 300 ? '2xx' : res.status < 500 ? '4xx' : '5xx')
el.methodPath.textContent = method + ' ' + path
el.timing.textContent = ms + 'ms'
el.body.className = 'response-body'
el.body.innerHTML = syntaxHighlight(data)
} catch (err) {
el.header.style.display = 'none'
el.body.className = 'response-body'
el.body.textContent = 'Network error: ' + err.message
}
const contentType = res.headers.get('content-type') || ''
const data = contentType.includes('application/json')
? await res.json()
: await res.text()
el.header.style.display = 'flex'
el.status.textContent = res.status
el.status.className = 'status status-' + (res.status < 300 ? '2xx' : res.status < 500 ? '4xx' : '5xx')
el.methodPath.textContent = method + ' ' + path
el.timing.textContent = ms + 'ms'
el.body.className = 'response-body'
if (typeof data === 'string') {
el.body.textContent = data
} else {
el.body.innerHTML = syntaxHighlight(data)
}
} catch (err) {
el.header.style.display = 'none'
el.body.className = 'response-body'
el.body.textContent = 'Network error: ' + err.message
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/orpc/src/ui.ts` around lines 244 - 257, The code currently assumes
every response is JSON (using await res.json()) and treats parse failures as
network errors; change the logic so after receiving res you check the
Content-Type (e.g., res.headers.get('content-type')) and if it contains
"application/json" parse with res.json() and render via syntaxHighlight(data),
otherwise use await res.text() and render the plain text/HTML into el.body (and
set an appropriate class like 'response-body text' or similar); ensure only real
network exceptions fall into the catch block and preserve updating el.header,
el.status, el.methodPath, and el.timing for non-JSON responses as well
(references: variables/res object, el, syntaxHighlight, method, path, ms).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/evlog/test/frameworks/orpc.test.ts`:
- Around line 412-424: The keep callback in the test 'lets the keep callback
force-keep based on context' is reading ctx.context.pinged but the procedure
sets pinged via context.log.set which populates ctx.event.pinged; update the
mockImplementation for keep to check ctx.event.pinged (and set ctx.shouldKeep =
true when present) so the force-keep branch is actually exercised (refer to the
mocked keep function and the test case name to locate the change).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13d5a153-78ae-47f4-b1f6-6dcb92d6be95

📥 Commits

Reviewing files that changed from the base of the PR and between 6532944 and 0c03927.

📒 Files selected for processing (4)
  • apps/docs/content/3.integrate/frameworks/15.orpc.md
  • examples/orpc/src/index.ts
  • packages/evlog/src/orpc/index.ts
  • packages/evlog/test/frameworks/orpc.test.ts

Comment on lines +412 to +424
it('lets the keep callback force-keep based on context', async () => {
const { drain, keep } = createPipelineSpies()
keep.mockImplementation((ctx) => {
if (ctx.context.pinged) ctx.shouldKeep = true
})
const { client } = buildClient({ drain, keep })

await client.ping({})
await waitForDrainCalls(drain)

expect(keep).toHaveBeenCalledOnce()
expect(drain).toHaveBeenCalledOnce()
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Test checks wrong property for force-keep behavior.

The keep callback checks ctx.context.pinged, but the procedure writes context.log.set({ pinged: true }) which populates ctx.event.pinged, not ctx.context.pinged. The test passes because both keep and drain are called once, but the conditional force-keep logic isn't actually being exercised.

🧪 Proposed fix
     it('lets the keep callback force-keep based on context', async () => {
       const { drain, keep } = createPipelineSpies()
       keep.mockImplementation((ctx) => {
-        if (ctx.context.pinged) ctx.shouldKeep = true
+        if (ctx.event.pinged) ctx.shouldKeep = true
       })
       const { client } = buildClient({ drain, keep })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('lets the keep callback force-keep based on context', async () => {
const { drain, keep } = createPipelineSpies()
keep.mockImplementation((ctx) => {
if (ctx.context.pinged) ctx.shouldKeep = true
})
const { client } = buildClient({ drain, keep })
await client.ping({})
await waitForDrainCalls(drain)
expect(keep).toHaveBeenCalledOnce()
expect(drain).toHaveBeenCalledOnce()
})
it('lets the keep callback force-keep based on context', async () => {
const { drain, keep } = createPipelineSpies()
keep.mockImplementation((ctx) => {
if (ctx.event.pinged) ctx.shouldKeep = true
})
const { client } = buildClient({ drain, keep })
await client.ping({})
await waitForDrainCalls(drain)
expect(keep).toHaveBeenCalledOnce()
expect(drain).toHaveBeenCalledOnce()
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/evlog/test/frameworks/orpc.test.ts` around lines 412 - 424, The keep
callback in the test 'lets the keep callback force-keep based on context' is
reading ctx.context.pinged but the procedure sets pinged via context.log.set
which populates ctx.event.pinged; update the mockImplementation for keep to
check ctx.event.pinged (and set ctx.shouldKeep = true when present) so the
force-keep branch is actually exercised (refer to the mocked keep function and
the test case name to locate the change).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Support orpc

1 participant